import io
import socket
import struct
import sys
import threading
import time
import picamera
import ultrasonic
from multiprocessing import Queue
import AhoEdgeRegisterService_pb2 as ae
import AhoEdgeRegisterService_pb2_grpc as aeg
import grpc

global remote_host
register_server = ("192.168.1.111", 50051)


# soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# while True:
#     try:
#         soc.connect(('localhost',4040))
#         soc.send(b'ACT:QUERY')
#         data = soc.recv(1024)
#         remote_host = data.decode()
#         print('get SP addr from localhost')
#         soc.close()
#         break
#     except:
#         print('Error one more time')
#         try:
#             time.sleep(1)
#         except:
#             exit(0)
#     finally:
#         pass
global event
event = threading.Event()
global sock
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('127.0.0.1', 6666))

class AhoEdgeClient(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.in_que = Queue(1)
        self.out_que = Queue(1)
        print(f"connecting to register server: {register_server}")
        self.channel = grpc.insecure_channel(register_server)
        print(f"success connected to {register_server}")
        self.stub = stub = aeg.RegisterServiceStub(self.channel)
    
    def get_pip(self):
        return (self.in_que, self.out_que)

    def run(self) -> None:
        while True:
            print("standby...")
            _ = self.in_que.get()
            print("got command. gRPC:getService calling")
            response = self.stub.getService(ae.QueryRequest(serviceName="avoid"))
            print("got gRPC response. write to out_que")
            self.out_que.put((response.ipAddress, response.port))



        


# if len(sys.argv) == 2:
#     remote_host = sys.argv[1]
# elif len(sys.argv) == 3:
#     remote_host = sys.argv[1]
#     remote_port = int(sys.argv[2])


class TransThread(threading.Thread):
    frame = 0
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    def __init__(self, client_pip):
        threading.Thread.__init__(self)
        self.send_que, self.recv_que = client_pip

    def run(self) -> None:
        #connection = client_socket.makefile('wb')
        print("send command to AhoEedgClient Thread to get server info")
        self.send_que.put(b'x')
        server_info = self.recv_que.get()
        print(f"success got server info {server_info}")

        try:
            print(f"try to connect {server_info}")
            self.server_socket.connect(server_info)
        except Exception as e:
            print(f"Error: {server_info}")
        print(f"success connected to server {server_info}")
        try:
            camera = picamera.PiCamera()
            camera.resolution = (640, 480)
            camera.start_preview()
            time.sleep(2)
            stream = io.BytesIO()
            for foo in camera.capture_continuous(stream, 'jpeg', burst=True):
                # time_stamp_dict[self.frame] = time.perf_counter()
                self.server_socket.send(struct.pack('<iiiiii', self.frame, stream.tell() + 24, 0, stream.tell(), int(ultrasonic.Distance()),int(time.time())))
                self.frame += 1
                #print(f"size of data: {(stream.tell() + 24)/1024} kb")
                # client_socket.flush()
                stream.seek(0)
                self.server_socket.send(stream.read())
                stream.seek(0)
                stream.truncate()
                echo_ = self.server_socket.recv(8)
                end_time = time.perf_counter()
                pack_id, time_stamp = struct.unpack("<ii", echo_)
                #print(f'time cost({pack_id}):  {end_time - time_stamp_dict[pack_id]:.3f}')
            self.server_socket.send(struct.pack('<L', 0))
            
        finally:
            #connection.close()
            self.server_socket.close()


aho_edge_client_thread = AhoEdgeClient()
trans_thread = TransThread(aho_edge_client_thread.get_pip())
aho_edge_client_thread.start()
trans_thread.start()
trans_thread.join()
aho_edge_client_thread.join()